package com.globallogic.javatrainings.sergiiivanov.model;

import java.io.Serializable;

import com.globallogic.javatrainings.sergiiivanov.model.Const.Discipline;
import com.globallogic.javatrainings.sergiiivanov.resources.ErrorCodes;

/**
 * Saves score records for the student until removing student record with
 * <b>StudentsManager.removeStudent(Student)</b>
 * 
 * @author Sergey
 * 
 */
public class ScoreRecord implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * defines what discipline was evaluated with this record
     */
    public final Discipline discipline;
    /**
     * saves course name where score was recorded
     */
    public final String courseName;
    /**
     * saves lecture name when score was recorded
     */
    public final String lectureName;
    /**
     * saves reason for the score
     */
    public final String scoreReason;
    /**
     * saves teacher name, who adds the score
     */
    public final String teacherName;
    /**
     * saves score value between {@link Const#MIN_SCORE} and
     * {@link Const#MAX_SCORE}
     */
    public final int score;
    private Teacher teacher;
    private Course course;
    private Student student;

    /**
     * Validates provided data and created new instance of ScoreRecord
     * 
     * @param scoreStudent - evaluated student reference
     * @param lectureLink - {@link Lecture}, not null, should have course, course should have teacher
     * @param scoreValue - int value between {@link Const#MIN_SCORE} and {@link Const#MAX_SCORE}
     * @param reason - free string
     * @throws UniversityWarning provided data not valid
     */
    public ScoreRecord(Student scoreStudent, Lecture lectureLink, int scoreValue, String reason) throws UniversityWarning {
        if(scoreStudent == null)
            throw new UniversityWarning(ErrorCodes.SCORE_STUDENT_NULL);
        if (lectureLink == null)
            throw new UniversityWarning(ErrorCodes.SCORE_LECTURE_NULL);
        if (lectureLink.getCourse() == null)
            throw new UniversityWarning(ErrorCodes.SCORE_COURSE_NULL);
        if (lectureLink.getCourse().getDiscipline() == null)
            throw new UniversityWarning(ErrorCodes.SCORE_COURSE_BROKEN_DISCIPLINE);
        if (lectureLink.getCourse().getTeacher() == null)
            throw new UniversityWarning(ErrorCodes.SCORE_NO_TEACHER);
        if (scoreValue < Const.MIN_SCORE || scoreValue > Const.MAX_SCORE)
            throw new UniversityWarning(ErrorCodes.SCORE_WRONG_VALUE);
        discipline = lectureLink.getCourse().getDiscipline();
        courseName = lectureLink.getCourse().getName();
        lectureName = lectureLink.getName();
        teacherName = lectureLink.getCourse().getTeacher().getName();
        scoreReason = reason;
        score = scoreValue;
        teacher = lectureLink.getCourse().getTeacher();
        lectureLink.getCourse().getTeacher().addScoreLink(this);
        course = lectureLink.getCourse();
        lectureLink.getCourse().addScoreLink(this);
    }

    /**
     * Links student to the score record. Once linked, link could not be changed<br>
     *<b>Not used - student added as a parameter into constructor</b>
     * 
     * @param s {@link Student}
     * @throws UniversityWarning student is null of already set
     *
     * 
     */
    @Deprecated
    protected void setStudent(Student s) throws UniversityWarning {
        if (s != null) {
            if (student == null) {
                student = s;
            } else {
                throw new UniversityWarning(ErrorCodes.SCORE_STUDENT_ASSIGNED);
            }
        } else {
            throw new UniversityWarning(ErrorCodes.SCORE_STUDENT_NULL);
        }
    }

    /**
     * @return {@link Teacher}, as it was set on creation or <b>null</b>
     */
    public Teacher getTeacher() {
        return teacher;
    }

    /**
     * @return {@link Course}, as it was set on creation or <b>null</b>
     */
    public Course getCourse() {
        return course;
    }

    /**
     * @return {@link Student}, as it was set in {@link #setStudent(Student)} or
     *         <b>null</b>
     */
    public Student getStudent() {
        return student;
    }

    /**
     * Removes link to teacher. Used before removing teacher.<br>
     * String {@link #teacherName} still saved
     */
    void removeTeacher() {
        if (teacher != null)
            teacher.removeScoreLink(this);
        teacher = null;
    }

    /**
     * Removes link to course. Used before removing course.<br>
     * String {@link #courseName} still saved
     */
    void removeCourse() {
        if (course != null)
            course.removeScore(this);
        course = null;
    }

    /**
     * Removes all links from and to the score record. Used before removing
     * score record.<br>
     * <i>Records are removed with Student</i><br>
     * Calls {@link #removeCourse()} {@link #removeTeacher()}
     */
    void removeLinks() {
        removeTeacher();
        removeCourse();
        student = null;
    }
}
